/**
 * 
 */
package furniture.items3d.model.tessellation;

import java.util.List;

import javax.vecmath.Point2d;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;

import furniture.items3d.bounds.Bounds3d;
import furniture.items3d.model.PipePrimitive;
import furniture.render3d.PointSet;
import furniture.render3d.Triangle;
import furniture.render3d.TriangleSet;


import static furniture.items3d.model.tessellation.Helper.*;

/**
 * @author Grill Balazs (balage.g@gmail.com)
 *
 */
public class PipeTessellator {

	protected Bounds3d bounds;
	
	public PipeTessellator(Bounds3d bounds){
		this.bounds = bounds;
	}
	
	/**
	 * Generate triangles of a pipe
	 * @param pipe
	 * @return
	 */
	public TriangleSet tessellate(PipePrimitive pipe){
		Point2d minmax = linebounds(pipe.point,pipe.dir,bounds);
		double min = minmax.x;
		double max = minmax.y;
		
		PointSet circle = circle(pipe.point, pipe.dir, pipe.outerDiameter/2.0);
		
		double all = max-min;
		int k = 10;
		double one = all/k;
		
		ItemSet result = new ItemSet();
		for(int i=0;i<k-1;i++){
			result.addSet(tessellate(pipe,circle,pipe.dir,min+i*one,min+(i+2)*one));
		}
		
		return result;
	}
	
	/**
	 * Generate 2 circles towards dir, and generate trianlges 
	 * between them
	 * @param circle
	 * @param dir
	 * @param min
	 * @param max
	 * @return
	 */
	public TriangleSet tessellate(PipePrimitive pipe, PointSet circle, Vector3d dir, double min, double max){	
		Vector3d v1 = new Vector3d(dir);
		v1.scale(min);
		
		Vector3d v2 = new Vector3d(dir);
		v2.scale(max);
		
		PointSet c1 = (PointSet)circle.copy();
		c1.translate(v1);
		PointSet c2 = (PointSet)circle.copy();
		c2.translate(v2);
		
		//body of pipe
		TriangleSet p = tessellate(c1,c2,pipe); 	
		
		//end of pipe
		PointSet smallcircle = circle(pipe.point, pipe.dir, pipe.innerDiameter/2.0);
		smallcircle.translate(v2);
		
		TriangleSet e = tessellate(c2,smallcircle,pipe);
		
		ItemSet result = new ItemSet();
		result.addSet(p);
		result.addSet(e);
		
		return result;
	}
	
	/**
	 * Generate triangles between the two circles creating a
	 * cylinder.
	 * @param circle1
	 * @param circle2
	 * @return
	 * @note this method assumes that the two circles contains 
	 * the same number of points
	 */
	public TriangleSet tessellate(PointSet circle1, PointSet circle2, PipePrimitive pipe){
		int splitlevel = 2;
		ItemSet t = new ItemSet();
		
		List<Point3d> c1 = circle1.getPoints();
		List<Point3d> c2 = circle2.getPoints();
		
		for(int i=0;i<c1.size();i++){
			Point3d p1 = c1.get(i);
			Point3d p2 = (i+1==c1.size()) ? c1.get(0) : c1.get(i+1);
			Point3d p3 = c2.get(i);
			Point3d p4 = (i+1==c2.size()) ? c2.get(0) : c2.get(i+1);
				
			if (pipe.color != null){
				Triangle t1 = new Triangle(p3,p2,p1);
				t1.fill = true;
				t1.paint = shade(pipe.color,triangleNorm(t1),Tessellator.light);
				t.addSet(t1.split(splitlevel));
				Triangle t2 = new Triangle(p2,p3,p4);
				t2.fill = true;
				t2.paint = shade(pipe.color,triangleNorm(t2),Tessellator.light);
				t.addSet(t2.split(splitlevel));
			}
			
		}
		
		return t;
	}
}
